/** \file spi.c
 **
 **  file
 **
 ** History:
 **   - Wednesday, November 06, 2013  1.0  Mark  First Version
 *************************************************************************/


/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
//#include "spi.h"
#include "includes.h"

/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/

/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/
uint8_t SpiRxBuffer[256];
uint8_t SpiRxIndex=0;

uint8_t SpiTxBuffer[256]="\r\nSPI Slaver output for test!\r\n";
uint8_t SpiTxIndex=0;
/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/

/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/
static FM3_MFS03_CSIO_TypeDef* SPI_Dev[8]={
		((FM3_MFS03_CSIO_TypeDef *)FM3_MFS0_CSIO_BASE),
		((FM3_MFS03_CSIO_TypeDef *)FM3_MFS1_CSIO_BASE),
		((FM3_MFS03_CSIO_TypeDef *)FM3_MFS2_CSIO_BASE),
		((FM3_MFS03_CSIO_TypeDef *)FM3_MFS3_CSIO_BASE),
		((FM3_MFS03_CSIO_TypeDef *)FM3_MFS4_CSIO_BASE),
		((FM3_MFS03_CSIO_TypeDef *)FM3_MFS5_CSIO_BASE),
		((FM3_MFS03_CSIO_TypeDef *)FM3_MFS6_CSIO_BASE),
		((FM3_MFS03_CSIO_TypeDef *)FM3_MFS7_CSIO_BASE)};

static volatile unsigned int* SPI_CS[8] = {
		NULL,					// MFS0
		&SPI_MASTER_CS3,		// MFS1
		NULL,					// MFS2
		&SPI_MASTER_CS1,		// MFS3
		NULL,					// MFS4
		NULL,					// MFS5
		&SPI_MASTER_CS2,		// MFS6
		&SPI_MASTER_CS4};		// MFS7
/*****************************************************************************
 *  DESCRIPTION:    Wait routine
 *
 *  PARAMETERS:     Wait time
 *
 *  RETURNS:        Nothing
 *****************************************************************************/
static void WaitDelay(uint16_t u16Wait1)
{
  volatile uint16_t U16Wait2;

  while(u16Wait1--)
  {
    U16Wait2 = 1;
    while(U16Wait2--);
  }
}

/*****************************************************************************
 *  DESCRIPTION:    Initialize MFS to SPI Master mode (CPOL = 0, CPHA = 0)
 *
 *  PARAMETERS:     u8Spi: channel of MFS; Baudrate: rate of SPI device
 *
 *  RETURNS:        TRUE of success, FALSE of failed
 *****************************************************************************/
boolean_t Spi_Master_Init(uint8_t u8Spi, uint32_t Baudrate)
{
	switch(u8Spi){
	case COMM_IF3:		// mfs1
		FM3_GPIO->PFR5 |= (1<<6)|(1<<7)|(1<<8);
		FM3_GPIO->EPFR07 = FM3_GPIO->EPFR07 & ~((3<<10)|(3<<12)|(3<<14)) |
							(1<<10)|(1<<12)|(1<<14);
		SPI_MASTER_CS3 = HIGH;
		SPI_CS3_DDR = OUTPUT;
        break;
	case COMM_IF1:		// mfs3
		FM3_GPIO->PFR5 |= (1<<0)|(1<<1)|(1<<2);
		FM3_GPIO->EPFR07 = FM3_GPIO->EPFR07 & ~((3<<26)|(3<<24)|(3<<22)) |
							(2<<26)|(2<<24)|(2<<22);
		SPI_MASTER_CS1 = HIGH;
		SPI_CS1_DDR = OUTPUT;
		break;
	case COMM_IF2:		// mfs6
		FM3_GPIO->PFR5 |= (1<<3)|(1<<4)|(1<<5);
		FM3_GPIO->EPFR08 = FM3_GPIO->EPFR08 & ~((3<<16)|(3<<18)|(3<<20)) |
							(1<<16)|(1<<18)|(1<<20);
		SPI_MASTER_CS2 = HIGH;
		SPI_CS2_DDR = OUTPUT;
		break;
	case COMM_IF4:		// mfs7
		FM3_GPIO->PFR5 |= (1<<9)|(1<<10)|(1<<11);
		FM3_GPIO->EPFR08 = FM3_GPIO->EPFR08 & ~((3<<22)|(3<<24)|(3<<26)) |
							(1<<22)|(1<<24)|(1<<26);
		SPI_MASTER_CS4 = HIGH;
		SPI_CS4_DDR = OUTPUT;
		break;
	default:
		return FALSE;
	}
	// Initialize CSIO synchronous mode
	SPI_Dev[u8Spi]->SMR =  0x4F;    // SOE, SCKE, SCINV, MSB first, operation mode 2
	//SPI_Dev[u8Spi]->SMR =  0x43;
	SPI_Dev[u8Spi]->SCR = 0xA0;		// reset, SPI, Master
	//SPI_Dev[u8Spi]->SCR =  0x20;    // CSIO reset, Master mode, SPI transfer

	SPI_Dev[u8Spi]->SSR =  0x80;    // 0x80 = clear receive error flag
	SPI_Dev[u8Spi]->ESCR = 0x00;

	SPI_Dev[u8Spi]->BGR = SPI_BAUDRATE(Baudrate);
	SPI_Dev[u8Spi]->SCR |= 0x03;     // RX, TX enable
	mfsn_type[u8Spi] = CSIO_MASTER;
	return TRUE;
}

/*****************************************************************************
 *  DESCRIPTION:    Initialize MFS to SPI salve mode (CPOL = 0, CPHA = 0)
 *
 *  PARAMETERS:     u8Spi: channel of MFS;
 *
 *  RETURNS:        TRUE of success, FALSE of failed
 *****************************************************************************/
boolean_t Spi_Slave_Init(uint8_t u8Spi)
{
	switch(u8Spi){
	case COMM_IF3:		// mfs1
		FM3_GPIO->PFR5 |= (1<<6)|(1<<7)|(1<<8);
		FM3_GPIO->EPFR07 = FM3_GPIO->EPFR07 & ~((3<<10)|(3<<12)|(3<<14)) |
							(1<<10)|(1<<12)|(1<<14);
		SPI_MASTER_CS3 = HIGH;
		SPI_CS3_DDR = INPUT;
		NVIC_ClearPendingIRQ(MFS1RX_IRQn);
		NVIC_EnableIRQ(MFS1RX_IRQn);
		NVIC_SetPriority(MFS1RX_IRQn, 10);	// MAX 15
        break;
	case COMM_IF1:		// mfs3
		FM3_GPIO->PFR5 |= (1<<0)|(1<<1)|(1<<2);
		FM3_GPIO->EPFR07 = FM3_GPIO->EPFR07 & ~((3<<26)|(3<<24)|(3<<22)) |
							(2<<26)|(2<<24)|(2<<22);
		SPI_MASTER_CS1 = HIGH;
		SPI_CS1_DDR = INPUT;
		NVIC_ClearPendingIRQ(MFS3RX_IRQn);
		NVIC_EnableIRQ(MFS3RX_IRQn);
		NVIC_SetPriority(MFS3RX_IRQn, 10);	// MAX 15
		break;
	case COMM_IF2:		// mfs6
		FM3_GPIO->PFR5 |= (1<<3)|(1<<4)|(1<<5);
		FM3_GPIO->EPFR08 = FM3_GPIO->EPFR08 & ~((3<<16)|(3<<18)|(3<<20)) |
							(1<<16)|(1<<18)|(1<<20);
		SPI_MASTER_CS2 = HIGH;
		SPI_CS2_DDR = INPUT;
		NVIC_ClearPendingIRQ(MFS6RX_IRQn);
		NVIC_EnableIRQ(MFS6RX_IRQn);
		NVIC_SetPriority(MFS6RX_IRQn, 10);	// MAX 15
		break;
	case COMM_IF4:		// mfs7
		FM3_GPIO->PFR5 |= (1<<9)|(1<<10)|(1<<11);
		FM3_GPIO->EPFR08 = FM3_GPIO->EPFR08 & ~((3<<22)|(3<<24)|(3<<26)) |
							(1<<22)|(1<<24)|(1<<26);
		SPI_MASTER_CS4 = HIGH;
		SPI_CS4_DDR = INPUT;
		NVIC_ClearPendingIRQ(MFS7RX_IRQn);
		NVIC_EnableIRQ(MFS7RX_IRQn);
		NVIC_SetPriority(MFS7RX_IRQn, 10);	// MAX 15
		break;
	default:
		return FALSE;
	}
	// Initialize CSIO synchronous mode
	SPI_Dev[u8Spi]->SMR =  0x4D;     // SOE, SCINV, MSB first, operation mode 2
	//SPI_Dev[u8Spi]->SMR =  0x41;
	SPI_Dev[u8Spi]->SCR = 0xF0;		 // CSIO reset, Slave mode, SPI transfer
	SPI_Dev[u8Spi]->SSR =  0x80;     // 0x80 = clear receive error flag
	SPI_Dev[u8Spi]->ESCR = 0x00;
	SPI_Dev[u8Spi]->BGR = 0x7FFF;
	SPI_Dev[u8Spi]->SCR |= 0x03;     // RX, TX enable
	mfsn_type[u8Spi] = CSIO_SLAVE;
	return TRUE;
}

boolean_t Spi_Deinit(uint8_t u8Spi)
{
	if(u8Spi>7)
        return FALSE;

	SPI_Dev[u8Spi]->SCR = 0x80; //reset
	SPI_Dev[u8Spi]->SMR = 0x00;
	SPI_Dev[u8Spi]->SSR = 0x80;	//clear error
	SPI_Dev[u8Spi]->ESCR = 0x00;
	return TRUE;
}
/*****************************************************************************
 *  DESCRIPTION:    Send data to and read data from Flash
 *
 *  PARAMETERS:     U8Spi: channel; u8Data: data for transfer
 *
 *  RETURNS:        u8Result
 *****************************************************************************/
static __INLINE uint8_t SPIByte(uint8_t u8Spi, uint8_t u8Data)
{
	uint8_t u8Result;
	if(u8Spi>7)
		return 0xFF;
	*SPI_CS[u8Spi] = LOW;
	WaitDelay(10);
	while (!(SPI_Dev[u8Spi]->SSR & 0x02)); 	// TDRE?
  	SPI_Dev[u8Spi]->TDR = u8Data;       	// write data

  	while (SPI_Dev[u8Spi]->SSR & 0x01);    	// wait for start of transmission (or ongoing)
  	while (!(SPI_Dev[u8Spi]->SSR & 0x01)); 	// wait for transmission finished (TBI)
	u8Result = SPI_Dev[u8Spi]->RDR;		  	// get receive data
	*SPI_CS[u8Spi-1] = HIGH;
	return (u8Result);
}

/***************************************************************************
 *  DESCRIPTION:    Send data to SPI device
 *
 *  PARAMETERS:     u8Spi:channel; u8Data: data
 *
 *  RETURNS:        none
 ****************************************************************************/
void SpiWriteByte(uint8_t u8Spi, uint8_t u8Data)
{
	SPIByte(u8Spi, u8Data);
}

/***************************************************************************
 *  DESCRIPTION:    read data from SPI device
 *
 *  PARAMETERS:     u8Spi: channel
 *
 *  RETURNS:        uint8_t
 ****************************************************************************/
uint8_t SpiReadByte(uint8_t u8Spi)
{
	uint8_t ret;
	ret = SPIByte(u8Spi, 0xff);
	return ret;
}

/***************************************************************************
 *  DESCRIPTION:    Send data buffer to SPI device
 *
 *  PARAMETERS:     u8Spi:channel; buff: data buffer pointer
 *
 *  RETURNS:        none
 ****************************************************************************/
void SpiWriteBuffer(uint8_t u8Spi, uint8_t* buff, uint8_t buffsize)
{
	while(buffsize--)
		SPIByte(u8Spi, *buff++);
}

/***************************************************************************
 *  DESCRIPTION:    SPI Slave set data
 *
 *  PARAMETERS:     u8Spi:channel; u8Data: data
 *
 *  RETURNS:        none
 ****************************************************************************/
void SlaveSetData(uint8_t u8Spi, uint8_t u8Data)
{
	SPI_Dev[u8Spi]->TDR = u8Data;   // set data
}
/***************************************************************************
 *  DESCRIPTION:    SPI Slave receive interrupt handler
 *
 *  PARAMETERS:     u8Spi:channel
 *
 *  RETURNS:        none
 ****************************************************************************/
void SpiRxIrqHandler(uint8_t u8Spi)
{
    uint8_t u8Data = SPI_Dev[u8Spi]->RDR;
	SpiRxBuffer[SpiRxIndex++] = u8Data;
    Uart_Putch(0, u8Data);  // echo
	//if(SpiRxIndex == 255)
	//	SpiRxIndex = 0;
	SlaveSetData(u8Spi,SpiTxBuffer[SpiTxIndex++]);
	if(SpiTxIndex == 32)
		SpiTxIndex = 0;
}
